/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { RuntimeConfig } from './bridge/JavaScriptExecutor';
import HashMap from '@ohos.util.HashMap';
import hilog from '@ohos.hilog';
import Context from '@ohos.application.context';
import deviceInfo from '@ohos.deviceInfo'

import { DefaultDevSupportManagerFactory } from './devSupport/DefaultDevSupportManagerFactory';
import { DevSupportManagerFactory } from './devSupport/DevSupportManagerFactory';
import { DevBundleDownloadListener } from './devSupport/DevBundleDownloadListener';
import { RequestHandler } from './packagerConnection/RequestHandler';
import { ArkExecutor } from './arkexecutor/ArkExecutor';
import { SurfaceDelegate } from './common/SurfaceDelegate';
import { ReactNativeHost } from './ReactNativeHost';
import { ArkExecutorFactory } from './arkexecutor/ArkExecutorFactory';
import { JSCExecutorFactory } from './jscexecutor/JSCExecutorFactory';
import { HermesExecutorFactory } from '../hermes/reactexecutor/HermesExecutorFactory';
import { HermesExecutor } from '../hermes/reactexecutor/HermesExecutor';
import { JSCExecutor } from './jscexecutor/JSCExecutor';
import { UIImplementationProvider } from './uimanager/UIImplementationProvider'
import { JavaScriptExecutorFactory } from './bridge/JavaScriptExecutorFactory'
import { JSBundleLoader } from './bridge/JSBundleLoader'
import { ReactInstanceManager } from './ReactInstanceManager'
import { JSIModulePackage } from './bridge/JSIModulePackage'
import { JSInterpreter } from './JSInterpreter'
import { SurfaceDelegateFactory } from './common/SurfaceDelegateFactory'
import { ReactContext } from './bridge/ReactContext'
import * as Communication from './common/Communication'

export class ReactInstanceManagerBuilder {
  private static readonly TAG: string = "ReactInstanceManagerBuilder";
  private readonly mApplication;
  private mContext: Context.AbilityContext;
  private mJSBundleResourceUrl?: string;
  private mJSBundleLoader?: JSBundleLoader;
  private mJSMainModulePath?: string;
  private mUseDeveloperSupport?: boolean;
  private mDevSupportManagerFactory?: DevSupportManagerFactory;
  private mUIImplementationProvider?: UIImplementationProvider;
  private mDevBundleDownloadListener?: DevBundleDownloadListener;
  private mJavaScriptExecutorFactory?: JavaScriptExecutorFactory;
  private mMinNumShakes = 1;
  private mMinTimeLeftInFrameForNonBatchedOperationMs = -1;
  private mJSIModulesPackage?: JSIModulePackage;
  private mCustomPackagerCommandHandlers?: HashMap<string, RequestHandler>;
  private mSurfaceDelegateFactory?: SurfaceDelegateFactory;
  private jsInterpreter: JSInterpreter = JSInterpreter.OLD_LOGIC;

  constructor() {
    hilog.info(0x0000, ReactInstanceManagerBuilder.TAG, 'constructor');
  }

  public static getDefaultJSBundleFile(): string | null {
    return null;
  }

  public static getDefaultBundleResourceName(): string | null {
    return "index.harmony.bundle";
  }

  public setAbilityContext(context: any) {
    this.mContext = context
    return this;
  }

  public setUIImplementationProvider(uiImplementationProvider?: UIImplementationProvider): ReactInstanceManagerBuilder {
    this.mUIImplementationProvider = uiImplementationProvider;
    return this;
  }

  public setJSIModulesPackage(jsiModulePackage: JSIModulePackage): ReactInstanceManagerBuilder {
    this.mJSIModulesPackage = jsiModulePackage;
    return this;
  }

  public setJavaScriptExecutorFactory(javaScriptExecutorFactory?: JavaScriptExecutorFactory): ReactInstanceManagerBuilder {
    this.mJavaScriptExecutorFactory = javaScriptExecutorFactory;
    return this;
  }

  public setBundleResourceName(bundleResourceName: string): ReactInstanceManagerBuilder {
    this.mJSBundleResourceUrl = bundleResourceName
    //this.mJSBundleResourceUrl = bundleResourceName ? "assets://" + bundleResourceName : bundleResourceName
    this.mJSBundleLoader = null;
    return this;
  }

  public setJSBundleFile(jsBundleFile: string): ReactInstanceManagerBuilder {
    if (jsBundleFile?.startsWith("worker")) {
      this.mJSBundleResourceUrl = jsBundleFile;
      this.mJSBundleLoader = null;
      return this;
    } else {
      // -> return this.setJSBundleLoader(JSBundleLoader.createDirectRunLoader(null, null, null));
      return this.setJSBundleLoader(JSBundleLoader.createFileLoader(jsBundleFile))
    }
  }

  public setJSBundleLoader(jsBundleLoader: JSBundleLoader): ReactInstanceManagerBuilder {
    this.mJSBundleLoader = jsBundleLoader;
    this.mJSBundleResourceUrl = null;
    return this;
  }

  public setJsEngineAsHermes(hermesEnabled: boolean): ReactInstanceManagerBuilder {
    if (hermesEnabled) {
      this.setJSEngine(JSInterpreter.HERMES);
    } else {
      this.setJSEngine(JSInterpreter.JSC);
    }
    return this;
  }

  public setJsEngineAsArk(arkEnabled: boolean): ReactInstanceManagerBuilder {
    if (arkEnabled) {
      this.setJSEngine(JSInterpreter.ARK);
    } else {
      this.setJSEngine(JSInterpreter.JSC);
    }
    return this;
  }

  public setJSMainModulePath(jsMainModulePath: string): ReactInstanceManagerBuilder {
    this.mJSMainModulePath = jsMainModulePath;
    return this;
  }

  public setSurfaceDelegateFactory(surfaceDelegateFactory: SurfaceDelegateFactory): ReactInstanceManagerBuilder {
    this.mSurfaceDelegateFactory = surfaceDelegateFactory;
    return this;
  }

  public setDevBundleDownloadListener(listener?: DevBundleDownloadListener): ReactInstanceManagerBuilder {
    this.mDevBundleDownloadListener = listener;
    return this;
  }

  public setMinNumShakes(minNumShakes: number): ReactInstanceManagerBuilder {
    this.mMinNumShakes = minNumShakes;
    return this;
  }

  public setCustomPackagerCommandHandlers(customPackagerCommandHandlers: HashMap<string, RequestHandler>): ReactInstanceManagerBuilder {
    this.mCustomPackagerCommandHandlers = customPackagerCommandHandlers;
    return this;
  }

  public setUseDeveloperSupport(useDeveloperSupport: boolean): ReactInstanceManagerBuilder {
    this.mUseDeveloperSupport = useDeveloperSupport;
    return this;
  }

  public setDevSupportManagerFactory(devSupportManagerFactory: DevSupportManagerFactory): ReactInstanceManagerBuilder {
    this.mDevSupportManagerFactory = devSupportManagerFactory;
    return this;
  }

  public build() {
    hilog.info(0x0000, ReactInstanceManagerBuilder.TAG, 'build');
    //      if (!this.mJSBundleResourceUrl && !this.mJSBundleLoader) {
    //        return;
    //      }

    let appName = this.mContext.applicationInfo.name//"myapplicationstage";
    let deviceName = deviceInfo.deviceType

    hilog.info(0x0000, ReactInstanceManagerBuilder.TAG, "appName: " +  this.mContext.applicationInfo.name + " deviceName: ", JSON.stringify(deviceInfo));

    hilog.info(0x0000, ReactInstanceManagerBuilder.TAG, `this.mJSBundleLoader == null && this.mJSBundleResourceUrl != null: ${this.mJSBundleLoader == null && this.mJSBundleResourceUrl != null}` )
    hilog.info(0x0000, ReactInstanceManagerBuilder.TAG, `this.mJSMainModulePath ${this.mJSMainModulePath} && this.mJSBundleResourceUrl: ${this.mJSBundleResourceUrl}` )


    let reactInstanceManager = new ReactInstanceManager(
      this.mContext,
      this.mJavaScriptExecutorFactory?? this.getDefaultJSExecutorFactory(appName, deviceName, this.mContext),
      this.mJSMainModulePath,
      this.mUIImplementationProvider, // ?? new UIImplementationProvider(),
      this.mJSIModulesPackage?? new JSIModulePackage(),
      this.mSurfaceDelegateFactory,
      (this.mJSBundleLoader == null && this.mJSBundleResourceUrl != null)
//        ? JSBundleLoader.createResourceLoader(this.mContext, this.mJSBundleResourceUrl, false /*Asynchronous*/)
        ? JSBundleLoader.createFileLoader("", this.mJSBundleResourceUrl, true /*Asynchronous*/)
        : this.mJSBundleLoader,
      this.mUseDeveloperSupport,
      this.mDevSupportManagerFactory?? new DefaultDevSupportManagerFactory(),
      this.mDevBundleDownloadListener,
      this.mMinNumShakes,
      this.mCustomPackagerCommandHandlers
    );

    ReactNativeHost.getInstance().setReactInstanceManager(reactInstanceManager)
  }

  private setJSEngine(jsInterpreter: JSInterpreter) {
    this.jsInterpreter = jsInterpreter;
  }

  private getDefaultJSExecutorFactory(appName: string, deviceName: string, abilityContext: Context.AbilityContext): JavaScriptExecutorFactory {
    if (this.jsInterpreter == JSInterpreter.ARK) {
      // ArkExecutor.loadLibrary();
      return new ArkExecutorFactory(new RuntimeConfig(0));
    } else if (this.jsInterpreter == JSInterpreter.OLD_LOGIC) {
      ReactInstanceManager.initializeSoLoaderIfNecessary(abilityContext);
      JSCExecutor.loadLibrary();
      return new JSCExecutorFactory(appName, deviceName);
    } else if (this.jsInterpreter == JSInterpreter.HERMES) {
      HermesExecutor.loadLibrary();
      return new HermesExecutorFactory();
    } else {
      JSCExecutor.loadLibrary();
      return new JSCExecutorFactory(appName, deviceName);
    }
  }
}
